package com.google.ant.extensions.types;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import com.google.ant.extensions.SourceRepo;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.DataType;

public class Modules extends DataType {
    private String id;
    private boolean builddep;
    private Vector modules = new Vector();

    public void setId(String i) {
        this.id = i;
    }

    public String getId() {
        return this.id;
    }

    public void setBuilddep(boolean b) {
        this.builddep = b;
    }

    @SuppressWarnings("unchecked")
    public void addModule(Module m) {
        modules.addElement(m);
    }

    public Vector getModules() {
        return modules;
    }

    private void loadModuleName(final SourceRepo repo, final Module module) {
        for (Module m : repo.get()) {
            if (m.equals(module)) {
                module.setName(m.getName());
                return;
            }
        }
        if (module.getName() == null) {
            module.setName(new File(module.getBasedir()).getName());
        }
    }

    protected boolean hasSubModules(final Module module) {
        return module.getName().endsWith("*");
    }
    
    protected void resolveParentModule(final Module module) {
        module.setName(module.getName().replace("*", ""));
    }

    public List<Module> list() {
        List<Module> builds = new ArrayList<Module>();
        SourceRepo repo = new SourceRepo(getProject());

        // Register first, to help the resolver to get all the dependencies of the modules
        for (Iterator iter = modules.iterator(); iter.hasNext();) {
            Module module = (Module) iter.next();
            File moduleBase = new File(getProject().getBaseDir(), module.getName());
            if (!moduleBase.exists()) {
                continue;
            }
            module.setBasedir(moduleBase.getAbsolutePath());
            module.selfRegister();
        }


        for (Iterator iter = modules.iterator(); iter.hasNext();) {
            Module module = (Module) iter.next();
            boolean hasSubModules = hasSubModules(module);
            if (hasSubModules) {
                resolveParentModule(module);
            }

            File moduleBase = new File(getProject().getBaseDir(), module.getName());
            module.setBasedir(moduleBase.getAbsolutePath());

            //System.out.println("ModuleBase: " + moduleBase);

            if (!hasSubModules && !module.hasBuildFile()) {
                String msg = "Can not find the " + module.getBuildfile() 
                    + " file under the module:" + module.getName();
                log(msg, Project.MSG_WARN);
            }

            loadModuleName(repo, module);
            if (builddep) {
                Collection<Module> deps = module.getDependencies();
                //System.out.println("Module:" + module.getName() + " " + deps);
                for (Module m : deps) {
                    if (!builds.contains(m)) {
                        builds.add(m);
                    }
                }
            } else {
                module.setBuilddep(false);
            }

            if (hasSubModules) {
                for (Module m : module.getSubModules()) {
                    loadModuleName(repo, m);
                    builds.add(m);
                }
            }
            
            if (module.hasBuildFile() && !hasSubModules) {
                builds.add(module);
            }
        }

        // Register into the SourceRepo if quolified

        for (Module module : builds) {
            module.selfRegister();
        }

        return builds;
    }

    public List<Module> listAll() {
        List<Module> allModules = new ArrayList<Module>();
        for (Module m : list()) {
            allModules.add(m);
            for (Module m2 : m.getDependencies()) {
                if (!allModules.contains(m2)) {
                    allModules.add(m2);
                }
            }
        }

        for (Module module : allModules) {
            module.selfRegister();
        }

        return allModules;
    }

    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("Modules <");
        sb.append(id);
        sb.append("> has modules : ");
        sb.append(modules.toString());
        return sb.toString();
    }
}
